/**************************************
*                                     *
*   Jeff Molofee's Basecode Example   *
*          nehe.gamedev.net           *
*                2001                 *
*                                     *
**************************************/

#include <windows.h>											// Header File For Windows
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gl\gl.h>												// Header File For The OpenGL32 Library
#include <gl\glu.h>												// Header File For The GLu32 Library
#include <gl\glaux.h>											// Header File For The GLaux Library
#include "NeHeGL.h"												// Header File For NeHeGL
#include <gl\glext.h>
#include <string.h>
#include "jpeglib.h"
#include "Shining3D.h"

#pragma comment( lib, "opengl32.lib" )							// Search For OpenGL32.lib While Linking
#pragma comment( lib, "glu32.lib" )								// Search For GLu32.lib While Linking
#pragma comment( lib, "glaux.lib" )								// Search For GLaux.lib While Linking
#pragma comment( lib, "jpeg.lib" )

tImageJPG *LoadJPG(const char *filename);
void CreateTexture(UINT textureArray[], LPSTR strFileName, int textureID);
UINT g_Texture[21] = {0};						// This holds the texture info, referenced by an ID #
#define SCENE 10

#ifndef CDS_FULLSCREEN											// CDS_FULLSCREEN Is Not Defined By Some
#define CDS_FULLSCREEN 4										// Compilers. By Defining It This Way,
#endif			

//PFNGLCOPYTEXIMAGE2DEXTPROC      glCopyTexImage2DEXT2         = 0;
bool movelight=false;
GL_Window*	g_window;
Keys*		g_keys;
POINT mpos;

GLfloat mp[]          = {  10.0f,  -3.7f,   0.0f        };
GLfloat pv[]          = {  10.0f,   6.0f,  15.0f        };
GLfloat rotv[]        = { 180.0f, 180.0f,   0.0f        }; /* rotation vector for scene */
GLfloat rotl[]        = {   0.0f,   0.0f,   0.0f        }; /* rotation vector for light */
GLfloat shadowcolor[] = {   2.0f,   2.0f,   2.0f,  2.0f };
GLfloat lv[]          = {  15.0f,  -4.0f,   0.0f,  1.0f };	/* default light position */
GLfloat lp[]          = {   5.0f,  -4.0f,   0.0f,  1.0f }; /* look at - for light */
GLfloat perspective_mat[16], modelview_mat[16], temp[16], modelview_mat2[16];
const	float piover180 = 0.0174532925f;
bool shadows=false;
bool shadow2=false;
bool showmap=false;
GLuint SHADOWMAP;
GLuint SHADOWMAP2;
GLuint BLANK;
int x, y;
int width = 800, height = 600;

static int do_light = 0;
static int do_proj = 0;		/* Use projective textures instead of */
				/* shadows */
GLboolean shadows_supported   = GL_FALSE;
const GLubyte *extensions;
GLenum depthMapFormat         = GL_LUMINANCE;
GLenum depthMapInternalFormat = GL_INTENSITY8;
static GLubyte *depthBuffer   = NULL;
int requiredSize;
static const GLfloat swBorderColor[4] = { 1.0, 1.0, 1.0, 1.0 };

MD2 ENEMY_LEADER;//[7];
MD2 ENEMY_LEADER_WEAPON;//[7];
TEXTURE ENEMY_LEADER_TEX;
TEXTURE ENEMY_LEADER_WEAPON_TEX;

static void generate_shadow_map(void);
static void create_scene();
static void generate_shadow_map(void);
static void render_light_view(void);


int
isExtensionSupported(const char *extension)
{
  const GLubyte *extensions = NULL;
  const GLubyte *start;
  GLubyte *where, *terminator;

  /* Extension names should not have spaces. */
  where = (GLubyte *) strchr(extension, ' ');
  if (where || *extension == '\0')
    return 0;
  extensions = glGetString(GL_EXTENSIONS);
  /* It takes a bit of care to be fool-proof about parsing the
     OpenGL extensions string. Don't be fooled by sub-strings,
     etc. */
  start = extensions;
  for (;;) {
    where = (GLubyte *) strstr((const char *) start, extension);
    if (!where)
      break;
    terminator = where + strlen(extension);
    if (where == start || *(where - 1) == ' ')
      if (*terminator == ' ' || *terminator == '\0')
        return 1;
    start = terminator;
  }
  return 0;
}


void DecodeJPG(jpeg_decompress_struct* cinfo, tImageJPG *pImageData)
{
	// Read in the header of the jpeg file
	jpeg_read_header(cinfo, TRUE);
	
	// Start to decompress the jpeg file with our compression info
	jpeg_start_decompress(cinfo);

	// Get the image dimensions and row span to read in the pixel data
	pImageData->rowSpan = cinfo->image_width * cinfo->num_components;
	pImageData->sizeX   = cinfo->image_width;
	pImageData->sizeY   = cinfo->image_height;
	
	// Allocate memory for the pixel buffer
	pImageData->data = new unsigned char[pImageData->rowSpan * pImageData->sizeY];
		
	// Here we use the library's state variable cinfo.output_scanline as the
	// loop counter, so that we don't have to keep track ourselves.
	
	// Create an array of row pointers
	unsigned char** rowPtr = new unsigned char*[pImageData->sizeY];
	for (int i = 0; i < pImageData->sizeY; i++)
		rowPtr[i] = &(pImageData->data[i*pImageData->rowSpan]);

	// Now comes the juice of our work, here we extract all the pixel data
	int rowsRead = 0;
	while (cinfo->output_scanline < cinfo->output_height) 
	{
		// Read in the current row of pixels and increase the rowsRead count
		rowsRead += jpeg_read_scanlines(cinfo, &rowPtr[rowsRead], cinfo->output_height - rowsRead);
	}
	
	// Delete the temporary row pointers
	delete [] rowPtr;

	// Finish decompressing the data
	jpeg_finish_decompress(cinfo);
}


///////////////////////////////// LOAD JPG \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
/////	This loads the JPG file and returns it's data in a tImageJPG struct
/////
///////////////////////////////// LOAD JPG \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

tImageJPG *LoadJPG(const char *filename)
{
	struct jpeg_decompress_struct cinfo;
	tImageJPG *pImageData = NULL;
	FILE *pFile;
	
	// This is the only function you should care about.  You don't need to
	// really know what all of this does (since you can't cause it's a library!) :)
	// Just know that you need to pass in the jpeg file name, and get a pointer
	// to a tImageJPG structure which contains the width, height and pixel data.
	// Be sure to free the data after you are done with it, just like a bitmap.
	
	// Open a file pointer to the jpeg file and check if it was found and opened 
	if((pFile = fopen(filename, "rb")) == NULL) 
	{
		// Display an error message saying the file was not found, then return NULL
//		MessageBox(g_hWnd, "Unable to load JPG File!", "Error", MB_OK);
		return NULL;
	}
	
	// Create an error handler
	jpeg_error_mgr jerr;

	// Have our compression info object point to the error handler address
	cinfo.err = jpeg_std_error(&jerr);
	
	// Initialize the decompression object
	jpeg_create_decompress(&cinfo);
	
	// Specify the data source (Our file pointer)	
	jpeg_stdio_src(&cinfo, pFile);
	
	// Allocate the structure that will hold our eventual jpeg data (must free it!)
	pImageData = (tImageJPG*)malloc(sizeof(tImageJPG));

	// Decode the jpeg file and fill in the image data structure to pass back
	DecodeJPG(&cinfo, pImageData);
	
	// This releases all the stored memory for reading and decoding the jpeg
	jpeg_destroy_decompress(&cinfo);
	
	// Close the file pointer that opened the file
	fclose(pFile);

	// Return the jpeg data (remember, you must free this data after you are done)
	return pImageData;
}

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *


///////////////////////////////// CREATE TEXTURE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
/////	This creates a texture in OpenGL that we can use as a texture map
/////
///////////////////////////////// CREATE TEXTURE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

void CreateTexture(UINT textureArray[], LPSTR strFileName, int textureID)
{
	if(!strFileName)									// Return from the function if no file name was passed in
		return;
	

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *	
	
	tImageJPG *pImage = LoadJPG(strFileName);			// Load the image and store the data

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
	

//	if(pImage == NULL)									// If we can't load the file, quit!


	// Generate a texture with the associative texture ID stored in the array
	glGenTextures(1, &textureArray[textureID]);

	// Bind the texture to the texture arrays index and init the texture
	glBindTexture(GL_TEXTURE_2D, textureArray[textureID]);

	// Build Mipmaps (builds different versions of the picture for distances - looks better)
	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, pImage->sizeX, pImage->sizeY, GL_RGB, GL_UNSIGNED_BYTE, pImage->data);

	// Lastly, we need to tell OpenGL the quality of our texture map.  GL_LINEAR is the smoothest.
	// GL_NEAREST is faster than GL_LINEAR, but looks blochy and pixelated.  Good for slower computers though.
	// Read more about the MIN and MAG filters at the bottom of main.cpp
		
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);//GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_NEAREST);//GL_LINEAR);	

	// Now we need to free the image data that we loaded since OpenGL stored it as a texture

	if (pImage)										// If we loaded the image
	{
		if (pImage->data)							// If there is texture data
		{
			free(pImage->data);						// Free the texture data, we don't need it anymore
		}

		free(pImage);								// Free the image structure
	}
}
static void render_normal_view(void)
{
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, g_Texture[2]);
  glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();
  gluLookAt(10, 10, 15,
	    0, 0, 0,
	    0, 1, 0);
  glRotatef(rotv[0], 1, 0, 0);
  glRotatef(rotv[1], 0, 1, 0);
  glRotatef(rotv[2], 0, 0, 1);
  glCallList(SCENE);

  glPopMatrix();

}
#define XFORM(cmds) \
  glMatrixMode(GL_TEXTURE); \
  cmds; \
  glMatrixMode(GL_MODELVIEW); \
  cmds

static void render_light_view(void)
{	

  glDisable      (GL_TEXTURE_2D);
  glColor3f      (1.0,1.0,1.0);
  glClear        (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glMatrixMode   (GL_MODELVIEW);
  glPushMatrix   ();
  glLoadIdentity ();
  glRotatef    ( 135  , 1, 0, 0 );// lookupdown angle 135
  glRotatef    ( 90, 0, 1, 0 );//heading 
//glRotatef    ( rotv[2]  , 0, 0, 1);
  glTranslatef ( -lv[0], -lv[1], -lv[2] );
//  gluLookAt(lv[0], lv[1], lv[2],
// 	          lp[0], lp[1], lp[2],
//	              0,     -1,     0);
//  glTranslatef (10.0, 10.0, 0.0);
//  glRotatef    (rotl[0], 1, 0, 0);
//  glRotatef    (rotl[1], 0, 1, 0);
//  glRotatef    (rotl[2], 0, 0, 1);
  glGetFloatv  (GL_MODELVIEW_MATRIX, modelview_mat);
  create_scene();
  glColor3f(0.15,0.15,0.15);
  XFORM(glPushMatrix();glTranslatef(mp[0],mp[1],mp[2]););//10.0, -3.0, 0.0); );
  
	glRotatef  ( 90, 0.0f, 1.0f, 0.0f);
	glRotatef  (180, 1.0f, 0.0f, 0.0f);

	glBindTexture(GL_TEXTURE_2D, ENEMY_LEADER_TEX.ID);
	glScalef(0.15f, 0.15f, 0.15f);
	ENEMY_LEADER.Animate(ENEMY_LEADER.stateStart, ENEMY_LEADER.stateEnd, 0.6f);
	XFORM(glPopMatrix());
//  glCallList   (SCENE);
  glPopMatrix  ();

}
static void render_light_view2(void)
{	

  glDisable      (GL_TEXTURE_2D);
  glColor3f      (1.0,1.0,1.0);
  glClear        (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glMatrixMode   (GL_MODELVIEW);
  glPushMatrix   ();
  glLoadIdentity ();
  glRotatef    ( 224  , 1, 0, 0 );// lookupdown
  glRotatef    ( 90, 0, 1, 0 );//heading 
//glRotatef    ( rotv[2]  , 0, 0, 1);
  glTranslatef ( -lv[0], -lv[1], -lv[2] );
//  gluLookAt(lv[0], lv[1], lv[2],
// 	          lp[0], lp[1], lp[2],
//	              0,     -1,     0);
//  glTranslatef (10.0, 10.0, 0.0);
//  glRotatef    (rotl[0], 1, 0, 0);
//  glRotatef    (rotl[1], 0, 1, 0);
//  glRotatef    (rotl[2], 0, 0, 1);
  glGetFloatv  (GL_MODELVIEW_MATRIX, modelview_mat2);
  create_scene();
  glColor3f(0.15,0.15,0.15);
  XFORM(glPushMatrix();glTranslatef(mp[0],mp[1],mp[2]););//10.0, -3.0, 0.0); );
  
	glRotatef  ( 90, 0.0f, 1.0f, 0.0f);
	glRotatef  (180, 1.0f, 0.0f, 0.0f);

	glBindTexture(GL_TEXTURE_2D, ENEMY_LEADER_TEX.ID);
	glScalef(0.15f, 0.15f, 0.15f);
	ENEMY_LEADER.Animate(ENEMY_LEADER.stateStart, ENEMY_LEADER.stateEnd, 0.6f);
	XFORM(glPopMatrix());
//  glCallList   (SCENE);
  glPopMatrix  ();

}

static void generate_shadow_map(void)
{
//  int x, y;
  GLfloat log2 = logf(2.0);
  
//  glColorMask(0,0,0,0);// Disable Colors - just need Depth Map

  x = 1<<((int) (logf((float) width)/log2));
  y = 1<<((int) (logf((float) height)/log2));
	
  glViewport(0, 0, x, y);

 	
  render_light_view2();
  glEnable(GL_TEXTURE_2D);
/*
   * Read in frame-buffer into a depth texture map
   */

#ifdef GL_SGIS_depth_texture
  if (do_proj)
#endif
  	  // Reads Pixels of our little window depth into a depthBuffer. 
      //glReadPixels(0, 0, x, y, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, depthBuffer);
      glReadPixels(0, 0, x, y, GL_LUMINANCE, GL_UNSIGNED_BYTE, depthBuffer);
      
#ifdef GL_SGIS_depth_texture
  else
  {
	glBindTexture(GL_TEXTURE_2D, SHADOWMAP2);

    glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16_SGIX,
			0, 0, x, y, 0);
  }
#endif


for (int wx = 0; wx<=x;wx++)
{ depthBuffer[wx]=0xff;depthBuffer[wx+(x*(y-1))]=0xff;}
for (int wy = 0; wy<=y;wy++)
{ depthBuffer[((x*wy)+(x-1))]=0xff; depthBuffer[ (x*wy)]=0xff;}

//GLenum depthMapFormat         = GL_LUMINANCE;
//GLenum depthMapInternalFormat = GL_INTENSITY8;

 if (!shadows_supported || do_proj)
 {
	   // Tranforms depthBuffer into a Luminance Texture.
          glBindTexture(GL_TEXTURE_2D, SHADOWMAP2);
   //       glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, swBorderColor);
          glTexImage2D(GL_TEXTURE_2D, 0, depthMapInternalFormat,
			  x, y, 0, depthMapFormat, GL_UNSIGNED_BYTE, depthBuffer);

 }
///////////////////////////////////////////////////
// A Messy Way To Generate two or more ShadowMaps
/////////////////////////////////////////////////////
  render_light_view();

  glEnable(GL_TEXTURE_2D);
  /*
   * Read in frame-buffer into a depth texture map
   */

#ifdef GL_SGIS_depth_texture
  if (do_proj)
#endif
  	  // Reads Pixels of our little window depth into a depthBuffer. 
      //glReadPixels(0, 0, x, y, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, depthBuffer);
      glReadPixels(0, 0, x, y, GL_LUMINANCE, GL_UNSIGNED_BYTE, depthBuffer);
#ifdef GL_SGIS_depth_texture
  else
  {
	glBindTexture(GL_TEXTURE_2D, SHADOWMAP);

    glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16_SGIX,
			0, 0, x, y, 0);
  }
#endif

for (int wx = 0; wx<=x;wx++)
{ depthBuffer[wx]=0xff;depthBuffer[wx+(x*(y-1))]=0xff;}
for (int wy = 0; wy<=y;wy++)
{ depthBuffer[((x*wy)+(x-1))]=0xff; depthBuffer[ (x*wy)]=0xff;}

//GLenum depthMapFormat         = GL_LUMINANCE;
//GLenum depthMapInternalFormat = GL_INTENSITY8;

 if (!shadows_supported || do_proj)
 {
	      // Tranforms depthBuffer into a Luminance Texture.
          glBindTexture(GL_TEXTURE_2D, SHADOWMAP);

          // glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, swBorderColor);
          glTexImage2D(GL_TEXTURE_2D, 0, depthMapInternalFormat,
			  x, y, 0, depthMapFormat, GL_UNSIGNED_BYTE, depthBuffer);

 }
/////////////////////////////////////////////////////////////////////////////////////
 glColorMask(1,1,1,1);  
 glViewport(0, 0, width, height);
 
}

/* are shadow extensions supported? */
// shadows_supported = GL_FALSE;



static void create_scene()
{
  GLfloat floor_col[] = {1.0, 1.0, 1.0};
  GLfloat floor_norm[] = {0.0, 0.0, 1.0};
  GLfloat floor_verts[4][3] = {{ 15.0, 0.0, 20.0}, { 5.0, 0.0, 20.0},
				               {5.0, 0.0, -10.0}, {  15.0, 0.0, -10.0}};
  GLfloat sphere_col[] = {1.0, 0.0, 0.0};
  GLfloat box_col[] = {0.0, 0.0, 1.0};
  GLfloat box_verts[6][4][3] = {
    {{ 1.0,-1.0,-1.0}, {-1.0,-1.0,-1.0}, {-1.0, 1.0,-1.0}, { 1.0, 1.0,-1.0}},
    {{ 1.0,-1.0, 1.0}, { 1.0,-1.0,-1.0}, { 1.0, 1.0,-1.0}, { 1.0, 1.0, 1.0}},
    {{-1.0,-1.0, 1.0}, { 1.0,-1.0, 1.0}, { 1.0, 1.0, 1.0}, {-1.0, 1.0, 1.0}},
    {{-1.0,-1.0,-1.0}, {-1.0,-1.0, 1.0}, {-1.0, 1.0, 1.0}, {-1.0, 1.0,-1.0}},
    {{ 1.0, 1.0, 1.0}, { 1.0, 1.0,-1.0}, {-1.0, 1.0,-1.0}, {-1.0, 1.0, 1.0}},
    {{ 1.0,-1.0,-1.0}, { 1.0,-1.0, 1.0}, {-1.0,-1.0, 1.0}, {-1.0,-1.0,-1.0}}};
  GLfloat box_norm[6][3] = {{0, 0, -1}, {1, 0, 0}, {0, 0, 1},
			   {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}};

  
  glBindTexture (GL_TEXTURE_2D, SHADOWMAP);
  if (shadow2) glBindTexture (GL_TEXTURE_2D, SHADOWMAP2);
 // glNewList(SCENE, GL_COMPILE);
  if (!shadows) glBindTexture (GL_TEXTURE_2D, g_Texture[1]);
//XFORM(glPushMatrix(); glTranslatef(0.0, 0.0, 0.0););

  glBegin(GL_QUADS);
  glTexCoord2f (2.0,1.0);
  glVertex3f   (15.0,0.0,20.0);
  glTexCoord2f (0.0,1.0);
  glVertex3f   (15.0,0.0,-10.0);
  glTexCoord2f (0.0,0.0);
  glVertex3f   (15.0,-10.0,-10.0);
  glTexCoord2f (2.0,0.0);
  glVertex3f   (15.0,-10.0,20.0);

  glTexCoord2f (2.0,1.0);
  glVertex3f   (5.0,  0.0,  20.0);
  glTexCoord2f (2.0,0.0);
  glVertex3f   (5.0,-10.0,  20.0);
  glTexCoord2f (0.0,0.0);
  glVertex3f   (5.0,-10.0, -10.0);
  glTexCoord2f (0.0,1.0);
  glVertex3f   (5.0,  0.0, -10.0);


  glEnd();
//  XFORM(glPopMatrix());
  if (!shadows) glBindTexture (GL_TEXTURE_2D, g_Texture[2]);
XFORM(glPushMatrix(); glTranslatef(0.0, 0.0, 0.0););
  glBegin(GL_QUADS);		/* draw the floor */
  glNormal3fv(floor_norm);
 // glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, floor_col);
//  glColor3f(floor_col[0],floor_col[1],floor_col[2]);
    glTexCoord2f(1.0,2.0);
    glVertex3fv(floor_verts[0]);
	glTexCoord2f(0.0,2.0);
    glVertex3fv(floor_verts[1]);
	glTexCoord2f(0.0,0.0);
    glVertex3fv(floor_verts[2]);
	glTexCoord2f(1.0,0.0);
    glVertex3fv(floor_verts[3]);
  glEnd();
   XFORM(glPopMatrix()); 
  
if (!shadows) glBindTexture (GL_TEXTURE_2D, g_Texture[0]);
XFORM(glPushMatrix(); glTranslatef(0.0, 0.0, 0.0););
  glBegin(GL_QUADS);		/* draw the floor */
  glNormal3fv(floor_norm);
 // glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, floor_col);
//  glColor3f(floor_col[0],floor_col[1],floor_col[2]);
    glTexCoord2f(2.0,2.0);
    glVertex3f(floor_verts[0][0],-10.0f,floor_verts[0][2]);
	glTexCoord2f(0.0,2.0);
    glVertex3f(floor_verts[1][0],-10.0f,floor_verts[1][2]);//    glVertex3fv(floor_verts[1]);
	glTexCoord2f(0.0,0.0);
    glVertex3f(floor_verts[2][0],-10.0f,floor_verts[2][2]);//    glVertex3fv(floor_verts[2]);
	glTexCoord2f(2.0,0.0);
    glVertex3f(floor_verts[3][0],-10.0f,floor_verts[3][2]);//    glVertex3fv(floor_verts[3]);
  glEnd();
   XFORM(glPopMatrix()); 
 //  XFORM(glPushMatrix();glTranslatef(0.0, 0.0, 0.0); );
  	//glTranslatef (LEADER_DATA[modelloop].mxpos, LEADER_DATA[modelloop].mypos,LEADER_DATA[modelloop].mzpos);
	//glRotatef    (LEADER_DATA[modelloop].mheading, 0, 1.0f, 0);
	//glRotatef(0, 1, 0, 0);
//	glEnable(GL_CULL_FACE); // added for speed
	//glCullFace(GL_FRONT); // added for speed

//	glBindTexture(GL_TEXTURE_2D, ENEMY_LEADER_TEX.ID);
//	glScalef(0.15f, 0.15f, 0.15f);
	
//	XFORM(glPopMatrix());
/*
  q = gluNewQuadric();
  XFORM(glPushMatrix();glTranslatef(11.0, -5.01, 1.0); );
//  glPushMatrix();
  //glLoadIdentity ();
  
//  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_col);
  glColor3f(sphere_col[0],sphere_col[1],sphere_col[2]);
  gluSphere(q, 1.0, 40, 40);
 // glPopMatrix();
  XFORM(glPopMatrix());

  XFORM(glPushMatrix();glTranslatef(9.0, -5.01, -1.0);)
 // glPushMatrix();
  //glLoadIdentity ();
//  glTranslatef(-1.0, -1.01, -1.0);
  for (i = 0; i < 6; i++) {
    glBegin(GL_QUADS);
 //   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, box_col);
	glColor3f(box_col[0],box_col[1],box_col[2]);
    glNormal3fv(box_norm[i]);
//	glTexCoord2f(0.0,0.0);
    glVertex3fv(box_verts[i][0]);
//	glTexCoord2f(1.0,0.0);
    glVertex3fv(box_verts[i][1]);
//	glTexCoord2f(1.0,1.0);
    glVertex3fv(box_verts[i][2]);
//	glTexCoord2f(0.0,1.0);
    glVertex3fv(box_verts[i][3]);
    glEnd();
  }
//  glPopMatrix();
  XFORM(glPopMatrix());
*/
  glColor3f(1.0,1.0,1.0);
//  glEndList();
}

BOOL Initialize (GL_Window* window, Keys* keys)					// Any GL Init Code & User Initialiazation Goes Here
{
	g_window	= window;
	g_keys		= keys;
 
	extensions = glGetString(GL_EXTENSIONS);
 
    if(isExtensionSupported("GL_SGIX_shadow_ambient") &&
       isExtensionSupported("GL_SGIX_shadow") &&
       isExtensionSupported("GL_SGIS_depth_texture"))
    shadows_supported = true;

//	glCopyTexImage2DEXT2 = (PFNGLCOPYTEXIMAGE2DEXTPROC) wglGetProcAddress("glCopyTexImage2DEXT");
	// Start Of User Initialization

	glClearColor (0.0f, 0.0f, 0.0f, 0.5f);						// Black Background
	glClearDepth (1.0f);										// Depth Buffer Setup
	glDepthFunc (GL_LEQUAL);            						// The Type Of Depth Testing (Less Or Equal)
	glEnable (GL_DEPTH_TEST);									// Enable Depth Testing
	glShadeModel (GL_SMOOTH);									// Select Smooth Shading
	glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);			// Set Perspective Calculations To Most Accurate

	CreateTexture(g_Texture, "ceiling.jpg", 0);
	CreateTexture(g_Texture, "walls.jpg", 1);
	CreateTexture(g_Texture, "stonefloor.jpg", 2);

  GLfloat ambient[]  = {0.1, 0.1, 0.1, 1.0};
  GLfloat diffuse[]  = {0.8, 0.7, 0.8, 1.0};
  GLfloat specular[] = {0.5, 0.6, 0.8, 1.0};
  GLfloat p[4];
  glGenTextures(1, &SHADOWMAP);
  glGenTextures(1, &SHADOWMAP2);
  glGenTextures(1, &BLANK);
//  create_scene();
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glClearDepth(1.0);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_POLYGON_SMOOTH);
//  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);

  glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
  glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
  glLightfv(GL_LIGHT0, GL_POSITION, lv);
  
  glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

  if(shadows_supported) {
#ifdef GL_SGIX_shadow_ambient
    glTexParameterf(GL_TEXTURE_2D, GL_SHADOW_AMBIENT_SGIX, 0.6);
#endif
#ifdef GL_SGIX_shadow
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_TRUE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_OPERATOR_SGIX,
		  GL_TEXTURE_LEQUAL_R_SGIX);
#endif
  }
  /*
   * Enable texgen to get texture-coods (x, y, z, w) at every
   * point.These texture co-ordinates are then transformed by the
   * texture matrix.
   */
  
  glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);//GL_EYE_LINEAR);
  glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);//GL_EYE_LINEAR);
  glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);//GL_EYE_LINEAR);
  glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);//GL_EYE_LINEAR);


  
  glBindTexture(GL_TEXTURE_2D,SHADOWMAP);
  p[0] = 1.0; p[1] = p[2] = p[3] = 0.0;
  glTexGenfv(GL_S, GL_OBJECT_PLANE, p);
 // glTexGenfv(GL_S, GL_EYE_PLANE, p);

  p[0] = 0.0; p[1] = 1.0; p[2] = p[3] = 0.0;
  glTexGenfv(GL_T, GL_OBJECT_PLANE, p);
//  glTexGenfv(GL_T, GL_EYE_PLANE, p);

  p[0] = p[1] = 0.0; p[2] = 1.0, p[3] = 0.0;
  glTexGenfv(GL_R, GL_OBJECT_PLANE, p);
//  glTexGenfv(GL_R, GL_EYE_PLANE, p);

  p[0] = p[1] = p[2] = 0.0; p[3] = 1.0;
  glTexGenfv(GL_Q, GL_OBJECT_PLANE, p);
 // glTexGenfv(GL_Q, GL_EYE_PLANE, p);

  glEnable(GL_TEXTURE_GEN_S);
  glEnable(GL_TEXTURE_GEN_T);
  glEnable(GL_TEXTURE_GEN_R);
  glEnable(GL_TEXTURE_GEN_Q);

  glBindTexture(GL_TEXTURE_2D, SHADOWMAP);
  
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glBindTexture(GL_TEXTURE_2D, SHADOWMAP2);
  
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    /* S and Q are always needed */
  requiredSize = (width+2) * (height+2);//* bytesPerDepthValue;
  depthBuffer = (GLubyte *)realloc(depthBuffer, requiredSize);

 // glCullFace(GL_BACK);
 // glEnable(GL_CULL_FACE);
  	ENEMY_LEADER_TEX.LoadJPG("ghost.jpg");//, GL_LINEAR, GL_LINEAR);
	ENEMY_LEADER.Load("tris.md2");
    ENEMY_LEADER.SetState(IDLE1);
  return TRUE;												// Return TRUE (Initialization Successful)
}

void Deinitialize (void)										// Any User DeInitialization Goes Here
{
}

void Update (double FPS)//DWORD milliseconds)								// Perform Motion Updates Here
{
	if (g_keys->keyDown [VK_ESCAPE] == TRUE)					// Is ESC Being Pressed?
	{
		TerminateApplication (g_window);						// Terminate The Program
	}

	if (g_keys->keyDown [VK_F1] == TRUE)						// Is F1 Being Pressed?
	{
		ToggleFullscreen (g_window);							// Toggle Fullscreen Mode
	}

	GetCursorPos(&mpos);				// Get The Current Mouse Position	( Add )

	if (g_keys->keyDown['S'] == TRUE)
	{
		showmap=true;
	}
	if (g_keys->keyDown['A'] == TRUE)
	{
		showmap=false;
	}
	if (g_keys->keyDown['I'] == TRUE)
	{
		mp[2]-=0.1f;
	}

	if (g_keys->keyDown['K'] == TRUE)
	{
		mp[2]+=0.1f;
	}
	if (g_keys->keyDown['J'] == TRUE)
	{
		mp[0]+=0.1f;
	}
	if (g_keys->keyDown['L'] == TRUE)
	{
		mp[0]-=0.1f;
	}
	float KM = .75;
               if ((g_keys->keyDown [VK_UP] ))//|| (g_keys->keyDown ['W'] ) )
				{	pv[0] += (float)sin(rotv[1]*piover180) * (0.25f +KM);
					pv[2] += (float)cos(rotv[1]*piover180) * (0.25f +KM);
				}
				if ((g_keys->keyDown [VK_DOWN]))//|| (g_keys->keyDown ['S'] ))
				{   pv[0] -= (float)sin(rotv[1]*piover180) * (0.25f + KM);
					pv[2] -= (float)cos(rotv[1]*piover180) * (0.25f + KM);
				}

				if ((g_keys->keyDown [VK_LEFT] ))//	|| ( g_keys->keyDown ['A'] ))    // ( Modified )
				{   pv[0] += (float)sin((rotv[1] - 90)*piover180)* (0.25f +KM);	// ( Modified )
					pv[2] += (float)cos((rotv[1] - 90)*piover180)* (0.25f +KM);	// ( Modified )
				}

				if (( g_keys->keyDown [VK_RIGHT]))// || (g_keys->keyDown ['D'] ))		// ( Modified )
				{	pv[0] += (float)sin((rotv[1] + 90)*piover180) * (0.25f +KM);	// ( Modified )
					pv[2] += (float)cos((rotv[1] + 90)*piover180) * (0.25f +KM);	// ( Modified )
				}
/*
	if (g_keys->keyDown[VK_LEFT] == TRUE)
	{
		lv[0]-=0.1;
	}

	if (g_keys->keyDown[VK_RIGHT] == TRUE)
	{
		lv[0]+=1;
	}
*/

//	SetCursorPos(320,240);				// Set The Mouse Position To The Center Of The Window	( Add )

	SetCursorPos(400,300);				// Set The Mouse Position To The Center Of The Window	( Add )

	rotv[1] -= (float)(400 - mpos.x)/50 * 5;         // Update The Direction For Movement		( Add )
	rotv[0] -= (float)(300 - mpos.y)/50 * 5;      // Update The X Rotation	( Add )

//	rotv[1] = 180.0*mpos.x/400.0 - 90.0;
//  rotv[0] = 180.0*mpos.y/400.0 - 90.0;



//	heading += (float)(320 - mpos.x)/100 * 5;         // Update The Direction For Movement		( Add )
//	yrot = heading;                                   // Update The Y Rotation	( Add )
//	lookupdown -= (float)(240 - mpos.y)/100 * 5;      // Update The X Rotation	( Add )
//	angle += (float)(milliseconds) / 5.0f;						// Update angle Based On The Clock
}

void Draw (void)
{
  /*
   * Render the scene with the light source as the viewpoint and save
   * the depth values in the texture map.
   */
 
  
  /*
   * Now render the normal scene using projective textures to get the
   * depth value from the light's point of view into the r-cood of the
   * texture.
   */
  glMatrixMode (GL_PROJECTION);										// Select The Projection Matrix
  glLoadIdentity ();													// Reset The Projection Matrix
  gluPerspective (90.0f, (GLfloat)(width)/(GLfloat)(height),			// Calculate The Aspect Ratio Of The Window
					1.0f, 4000.0f);	
  generate_shadow_map();

  glDisable(GL_TEXTURE_GEN_S);
  glDisable(GL_TEXTURE_GEN_T);
  glDisable(GL_TEXTURE_GEN_R);
  glDisable(GL_TEXTURE_GEN_Q);

  glClear      (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glGetFloatv  (GL_PROJECTION_MATRIX, perspective_mat);
  
  glMatrixMode   (GL_MODELVIEW);
  glLoadIdentity ();

  glEnable      (GL_TEXTURE_2D);
  glTexEnvi     (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 
  float sceneroty = 360.0f - rotv[1];
//gluLookAt    ( 10, 10, 10, 0, 0, 0, 0, 1, 0);
  glRotatef    ( rotv[0]  , 1, 0, 0 );
  glRotatef    ( sceneroty, 0, 1, 0 );//(rotv[1], 0, 1, 0);
//glRotatef    ( rotv[2]  , 0, 0, 1);
  glTranslatef ( -pv[0], pv[1], -pv[2] );
  shadows=false;
  create_scene();
GLUquadric *q;
  
  glMatrixMode   (GL_MODELVIEW);
  glPushMatrix   ();
  glLoadIdentity ();
  glTranslatef ( lv[0], lv[1], lv[2] );
    q = gluNewQuadric();
  glColor3f(1.0f,1.0f,0.0f);
  gluSphere(q, 0.5f,10, 10);
  glPopMatrix();
  
  
  glPushMatrix();
  glTranslatef(mp[0],mp[1],mp[2]);

	glRotatef ( 90, 0.0f, 1.0f, 0.0f);
	glRotatef (180, 1.0f, 0.0f, 0.0f);

	glBindTexture(GL_TEXTURE_2D, ENEMY_LEADER_TEX.ID);
	glScalef(0.15f, 0.15f, 0.15f);
	ENEMY_LEADER.Animate(ENEMY_LEADER.stateStart, ENEMY_LEADER.stateEnd, 0.6f);
  glPopMatrix();


  glGetFloatv (GL_PROJECTION_MATRIX, perspective_mat);
  glEnable    (GL_TEXTURE_2D);
  glEnable    (GL_TEXTURE_GEN_S);
  glEnable    (GL_TEXTURE_GEN_T);
  glEnable    (GL_TEXTURE_GEN_R);
  glEnable    (GL_TEXTURE_GEN_Q);
  
  glMatrixMode   (GL_TEXTURE);
  glPushMatrix   ();
  glLoadIdentity ();

  glTranslatef  (0.50, 0.50, 0.4994); // slightly move for shadow texture
  glScalef      (0.5, 0.5, 0.5);      // resize shadow texture
  glMultMatrixf (perspective_mat);    
  glMultMatrixf (modelview_mat);
 
  glMatrixMode  (GL_MODELVIEW);

  glPushMatrix  ();
  glColor3f     (0.25,0.25,0.25);
  glBindTexture (GL_TEXTURE_2D, SHADOWMAP);

  glTexEnvi     (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

//glBlendFunc   (GL_ZERO, GL_SRC_COLOR);    //OK BLEND
  glBlendFunc   (GL_DST_COLOR,GL_SRC_COLOR); //BETTER BLEND
 // glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
  glEnable      (GL_BLEND);
  shadows=true;
  shadow2=false;
  create_scene();
//  create_scene();
  //  glCallList    (SCENE);
  glDisable     (GL_BLEND);


  glMatrixMode  (GL_MODELVIEW);
  glPopMatrix   ();
  glMatrixMode  (GL_TEXTURE);
  glPopMatrix   ();
  
/////////////////////////////////////////////////
  glMatrixMode   (GL_TEXTURE);
  glPushMatrix   ();
  glLoadIdentity ();

  glTranslatef  (0.50, 0.50, 0.4994); // slightly move for shadow texture
  glScalef      (0.5 , 0.5 , 0.5);      // resize shadow texture
  glMultMatrixf (perspective_mat);    
  glMultMatrixf (modelview_mat2);
 
  glMatrixMode  (GL_MODELVIEW);

  glPushMatrix  ();

  glBindTexture (GL_TEXTURE_2D, SHADOWMAP2);

  glTexEnvi     (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_MODULATE);

  glBlendFunc   (GL_DST_COLOR,GL_SRC_COLOR); //BETTER BLEND

  glEnable      (GL_BLEND);
  shadows=true;
  shadow2=true;

  create_scene();

  glDisable     (GL_BLEND);


  glMatrixMode  (GL_MODELVIEW);
  glPopMatrix   ();
  glMatrixMode  (GL_TEXTURE);
  glPopMatrix   ();
/////////////////////////////////////////////////////////
if (showmap) render_light_view();
   
   glMatrixMode (GL_PROJECTION);										// Select The Projection Matrix

	glLoadIdentity ();													// Reset The Projection Matrix
	gluPerspective (45.0f, (GLfloat)(width)/(GLfloat)(height),			// Calculate The Aspect Ratio Of The Window
					1.0f, 4000.0f);												// Reset The Projection Matrix
  
//  glMatrixMode(GL_MODELVIEW);
//  glPopMatrix();


  glFlush       ();													// Flush The GL Rendering Pipeline
}
